use crate::error::Result;
use crate::types::Value;

/// Column information
#[derive(Debug, Clone, PartialEq)]
/// 列信息结构体，用于存储数据库列的相关元数据
pub struct ColumnInfo {
    /// 列名称
    pub name: String,
    /// 数据类型，使用 u32 表示类型标识
    pub data_type: u32,
    /// 标识该列是否允许为空
    pub nullable: bool,
    /// 可选字段，表示列的精度，某些数据类型可能没有精度信息
    pub precision: Option<u32>,
    /// 可选字段，表示列的小数位数，某些数据类型可能没有小数位数信息
    pub scale: Option<u32>,
}

/// Query result
#[derive(Debug, Clone)]
pub struct QueryResult {
    rows: Vec<Vec<Value>>,
    columns: Vec<ColumnInfo>,
    affected_rows: u64,
    command_tag: Option<String>,
}

impl QueryResult {
    /// Create a new query result from rows and columns
    pub fn from_rows(rows: Vec<Vec<Value>>, columns: Vec<ColumnInfo>) -> Self {
        Self {
            rows,
            columns,
            affected_rows: 0,
            command_tag: None,
        }
    }

    /// Create a query result from command execution
    pub fn from_command(affected_rows: u64, command_tag: Option<String>, _query: String) -> Self {
        Self {
            rows: Vec::new(),
            columns: Vec::new(),
            affected_rows,
            command_tag,
        }
    }

    /// Get all rows
    pub fn rows(&self) -> &[Vec<Value>] {
        &self.rows
    }

    /// Get columns
    pub fn columns(&self) -> &[ColumnInfo] {
        &self.columns
    }

    /// Get affected rows count
    pub fn affected_rows(&self) -> u64 {
        self.affected_rows
    }

    /// Get command tag
    pub fn command_tag(&self) -> Option<&str> {
        self.command_tag.as_deref()
    }

    /// Get number of rows
    pub fn len(&self) -> usize {
        self.rows.len()
    }

    /// Check if result is empty
    pub fn is_empty(&self) -> bool {
        self.rows.is_empty()
    }

    /// Get a specific row
    pub fn get(&self, index: usize) -> Option<&[Value]> {
        self.rows.get(index).map(|row| row.as_slice())
    }

    /// Convert to iterator over rows
    pub fn iter(&self) -> std::slice::Iter<'_, Vec<Value>> {
        self.rows.iter()
    }

    /// Create an empty query result
    pub fn empty() -> Self {
        Self {
            rows: Vec::new(),
            columns: Vec::new(),
            affected_rows: 0,
            command_tag: None,
        }
    }
}

/// Prepared statement
#[derive(Debug, Clone)]
pub struct Statement {
    client: crate::client::Client,
    id: String,
    query: String,
    parameters: Vec<Value>,
}

impl Statement {
    /// Create a new statement
    pub fn new(client: crate::client::Client, id: String, query: String) -> Self {
        Self {
            client,
            id,
            query,
            parameters: Vec::new(),
        }
    }

    /// Get statement ID
    pub fn id(&self) -> &str {
        &self.id
    }

    /// Get SQL
    pub fn sql(&self) -> &str {
        &self.query
    }

    /// Get parameters
    pub fn parameters(&self) -> &[Value] {
        &self.parameters
    }

    /// Add parameter
    pub fn add_param(&mut self, value: Value) {
        self.parameters.push(value);
    }

    /// Clear parameters
    pub fn clear_params(&mut self) {
        self.parameters.clear();
    }

    /// Execute the prepared statement with parameters
    pub async fn execute(&self, params: &[Value]) -> Result<u64> {
        let client = &self.client;
        let mut conn = client.connection.lock().await;
        let result = conn.execute_prepared(&self.id, params).await?;
        Ok(result.affected_rows())
    }
}

/// Transaction
#[derive(Debug)]
pub struct Transaction {
    client: crate::client::Client,
    committed: bool,
    rolled_back: bool,
}

impl Transaction {
    /// Create a new transaction
    pub fn new(client: crate::client::Client) -> Self {
        Self {
            client,
            committed: false,
            rolled_back: false,
        }
    }

    /// Commit the transaction
    pub async fn commit(&mut self) -> Result<()> {
        if !self.committed && !self.rolled_back {
            self.client.query("COMMIT").await?;
            self.committed = true;
        }
        Ok(())
    }

    /// Rollback the transaction
    pub async fn rollback(&mut self) -> Result<()> {
        if !self.committed && !self.rolled_back {
            self.client.query("ROLLBACK").await?;
            self.rolled_back = true;
        }
        Ok(())
    }

    /// Execute a query within the transaction
    pub async fn query(&self, query: &str) -> Result<QueryResult> {
        self.client.query(query).await
    }

    /// Execute a statement within the transaction
    pub async fn execute(&self, query: &str, params: &[Value]) -> Result<u64> {
        let stmt = self.client.prepare(query).await?;
        stmt.execute(params).await
    }
}
impl Drop for Transaction {
    fn drop(&mut self) {
        if !self.committed && !self.rolled_back {
            // 在异步环境中，我们不能在Drop中执行异步操作
            // 记录警告并让用户手动处理回滚
            log::warn!("Transaction dropped without explicit commit or rollback. Consider using explicit rollback.");
            
            // 注意：在异步Rust中，Drop不能执行异步操作
            // 用户应该显式调用rollback()或commit()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_query_result_from_rows() {
        let rows = vec![vec![Value::Int(1), Value::String("test".to_string())]];
        let columns = vec![
            ColumnInfo {
                name: "id".to_string(),
                data_type: 23,
                nullable: false,
                precision: None,
                scale: None,
            },
            ColumnInfo {
                name: "name".to_string(),
                data_type: 25,
                nullable: true,
                precision: None,
                scale: None,
            },
        ];

        let result = QueryResult::from_rows(rows.clone(), columns.clone());
        assert_eq!(result.rows().len(), 1);
        assert_eq!(result.columns().len(), 2);
        assert_eq!(result.affected_rows(), 0);
    }

    #[test]
    fn test_query_result_from_command() {
        let result = QueryResult::from_command(5, Some("INSERT 5".to_string()), "INSERT INTO users VALUES (1, 'test')".to_string());
        assert_eq!(result.affected_rows(), 5);
        assert_eq!(result.command_tag(), Some("INSERT 5"));
        assert!(result.is_empty());
    }

    
}